import {
  Bone,
  CylinderGeometry,
  DoubleSide,
  Float32BufferAttribute,
  Group,
  MeshPhongMaterial,
  QuaternionKeyframeTrack,
  Skeleton,
  SkinnedMesh,
  Uint16BufferAttribute,
  Vector3,
  Quaternion,
  AnimationClip,
  AnimationMixer,
} from 'three'
const segementHeight = 40 //每段骨骼长度
const segmentCount = 3 //骨骼数量
const height = segementHeight * segmentCount //骨架总高度
const halfHeight = height * 0.5
const sizing = {
  segementHeight,
  segmentCount,
  height,
  halfHeight,
}
// 创建柱体
const geometry = new CylinderGeometry(
  5,
  5,
  sizing.height,
  8,
  sizing.segmentCount * 3
)
const vertex = new Vector3()
const position = geometry.attributes.position

const skinIndices = []
const skinWeights = []

for (let i = 0; i < position.count; i++) {
  vertex.fromBufferAttribute(position, i)
  const y = vertex.y + sizing.halfHeight
  const skinIndex = Math.floor(y / sizing.segementHeight)
  const skinWeight = (y % sizing.segementHeight) / sizing.segementHeight
  skinIndices.push(skinIndex, skinIndex + 1, 0, 0)
  skinWeights.push(1 - skinWeight, skinWeight, 0, 0)
}

geometry.setAttribute('skinIndex', new Uint16BufferAttribute(skinIndices, 4))
geometry.setAttribute('skinWeight', new Float32BufferAttribute(skinWeights, 4))

// 添加骨骼
const bones = []
let prevBone = new Bone()
bones.push(prevBone)
prevBone.position.y = -sizing.halfHeight
for (let i = 0; i < sizing.segmentCount; i++) {
  const bone = new Bone()
  bone.position.y = sizing.segementHeight
  bones.push(bone)
  prevBone.add(bone)
  prevBone = bone
}

// 创造骨架
export const skeleton = new Skeleton(bones)
export const rootBone = skeleton.bones[0]
export const boneContainer = new Group()
boneContainer.add(rootBone)

// 添加材质
const material = new MeshPhongMaterial({
  skinning: true, //允许蒙皮动画
  color: 0x156289,
  emissive: 0x072534,
  side: DoubleSide,
  flatShading: true,
})

// 创建骨骼网络模型
export const skinnedMesh = new SkinnedMesh(geometry, material)
skinnedMesh.add(rootBone)
skinnedMesh.bind(skeleton)

skinnedMesh.translateX(-100)
skinnedMesh.translateY(100)

const xAxis = new Vector3(1, 0, 0)
const qInitial = new Quaternion().setFromAxisAngle(xAxis, 0)
const qFinal = new Quaternion().setFromAxisAngle(xAxis, Math.PI / 2)
skeleton.bones[1].name = 'bone1' //为骨头添加唯一名称
skeleton.bones[2].name = 'bone2'
skeleton.bones[3].name = 'bone3'
const routeKF = new QuaternionKeyframeTrack(
  'bone1.quaternion',//结合动画类型与骨头名称
  [0, 1, 2],
  [
    qInitial.x,
    qInitial.y,
    qInitial.z,
    qInitial.w,
    qFinal.x,
    qFinal.y,
    qFinal.z,
    qFinal.w,
    qInitial.x,
    qInitial.y,
    qInitial.z,
    qInitial.w,
  ]
)
const routeKF2 = new QuaternionKeyframeTrack(
  'bone2.quaternion',
  [0, 1, 2],
  [
    qInitial.x,
    qInitial.y,
    qInitial.z,
    qInitial.w,
    qFinal.x,
    qFinal.y,
    qFinal.z,
    qFinal.w,
    qInitial.x,
    qInitial.y,
    qInitial.z,
    qInitial.w,
  ]
)
const routeKF3 = new QuaternionKeyframeTrack(
  'bone3.quaternion',
  [0, 1, 2],
  [
    qInitial.x,
    qInitial.y,
    qInitial.z,
    qInitial.w,
    qFinal.x,
    qFinal.y,
    qFinal.z,
    qFinal.w,
    qInitial.x,
    qInitial.y,
    qInitial.z,
    qInitial.w,
  ]
)
const clip = new AnimationClip('skeletionAction', 3, [
  routeKF,
  routeKF2,
  routeKF3,
])

export function skeletonAnimation(playable) {
  if (!playable) return
  // 动画管理
  const mixer = new AnimationMixer(skinnedMesh)
  const clipAction = mixer.clipAction(clip) //实例化AnimationAction
  clipAction.play()
  return mixer
}
